看完怎麼建立路由之後,我們來看看當使用者發出請求時,Laravel 會怎麼進行處理。
使用者發出的請求,都會經過 public/index.php
裡面
use Illuminate\Http\Request;
//...
// Bootstrap Laravel and handle the request...
(require_once __DIR__.'/../bootstrap/app.php')
->handleRequest(Request::capture());
的這段程式。
這段會呼叫到 Application
的 handleRequest()
我們來看看其實作內容
/**
* Handle the incoming HTTP request and send the response to the browser.
*
* @param \Illuminate\Http\Request $request
* @return void
*/
public function handleRequest(Request $request)
{
$kernel = $this->make(HttpKernelContract::class);
$response = $kernel->handle($request)->send();
$kernel->terminate($request, $response);
}
如果和以前的 Laravel 框架比較,會發現這一段似乎在哪邊看過。
其實這一段在以前的 Laravel 框架,是直接放在 public/index.php
裡面的,在最近的改版內才封裝在 Application
的 handleRequest()
內。
在這邊, Laravel 先建立一個 $kernel
物件,透過 $kernel
的 handle()
將使用者請求轉換為 $response
之後,接著就是送出 $response
並將整個 $kernel
終止。
很單純對嗎?其實整個 Laravel 框架所做的事情就是這麼單純:接收請求、建立核心處理請求、回傳回應。
這邊的細節自然包含在 handle()
裡面:
/**
* Handle an incoming HTTP request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function handle($request)
{
$this->requestStartedAt = Carbon::now();
try {
$request->enableHttpMethodParameterOverride();
$response = $this->sendRequestThroughRouter($request);
} catch (Throwable $e) {
$this->reportException($e);
$response = $this->renderException($request, $e);
}
$this->app['events']->dispatch(
new RequestHandled($request, $response)
);
return $response;
}
我們想要關注的是這段邏輯內怎麼將請求分配給路由,所以要看 sendRequestThroughRouter()
。
sendRequestThroughRouter()
的實作則是
/**
* Send the given request through the middleware / router.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
protected function sendRequestThroughRouter($request)
{
$this->app->instance('request', $request);
Facade::clearResolvedInstance('request');
$this->bootstrap();
return (new Pipeline($this->app))
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
}
這邊建立了一個 Pipeline
物件,並將 $request
送入
protected function dispatchToRouter()
{
return function ($request) {
$this->app->instance('request', $request);
return $this->router->dispatch($request);
};
}
這邊 dispatch()
的實作則是
/**
* Dispatch the request to the application.
*
* @param \Illuminate\Http\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function dispatch(Request $request)
{
$this->currentRequest = $request;
return $this->dispatchToRoute($request);
}
/**
* Dispatch the request to a route and return the response.
*
* @param \Illuminate\Http\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function dispatchToRoute(Request $request)
{
return $this->runRoute($request, $this->findRoute($request));
}
到這邊,我們已經追到相當細節的實作階段,在這個階段裡執行的事情就是路由要做的兩件事:找到對應路由、執行該路由要做的事情並回傳 Response
物件。